package com.kx.center.service.impl;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import com.kx.center.common.CustomHashMap;
import com.kx.center.entity.Allocation;
import com.kx.center.entity.AllocationDetail;
import com.kx.center.entity.Goods;
import com.kx.center.entity.query.QueryAllocation;
import com.kx.center.entity.query.QueryResult;
import com.kx.center.exception.InventoryShortageException;
import com.kx.center.mappers.AllocationMapper;
import com.kx.center.mappers.GoodsMapper;
import com.kx.center.service.AllocationService;
import com.kx.center.util.SerialNumber;

@Service
public class AllocationServiceImpl implements AllocationService {
	
	@Autowired
	AllocationMapper mapper;
	
	@Autowired
	GoodsMapper goodsMapper;

	@Override
	public void insertAllocation(Allocation entity) {
		mapper.insertAllocation(entity);
	}

	@Override
	public void insertAllocationDetail(AllocationDetail entity) {
		mapper.insertAllocationDetail(entity);
	}

	@Override
	public void updateAllocation(Allocation entity) {
		mapper.updateAllocation(entity);
	}

	@Override
	public void updateAllocationDetail(AllocationDetail entity) {
		mapper.updateAllocationDetail(entity);
	}

	@Override
	public Allocation findAllocationById(Integer id) {
		return mapper.findAllocationById(id);
	}

	@Override
	public List<Allocation> findAllocationByStoreId(Integer storeId) {
		return mapper.findAllocationByStoreId(storeId);
	}

	@Override
	public List<Allocation> findAllocationByFromId(Integer storeId) {
		return mapper.findAllocationByFromId(storeId);
	}

	@Override
	public List<Allocation> findAllocationByToId(Integer storeId) {
		return mapper.findAllocationByToId(storeId);
	}

	@Override
	public List<AllocationDetail> findAllocationDetailByAllocationId(Integer allocationId) {

		List<AllocationDetail> result = new ArrayList<AllocationDetail>();
		List<AllocationDetail> list = mapper.findAllocationDetailByAllocationId(allocationId);
		
		for(AllocationDetail item : list) {
			if(item.getQuantity() > 0)
				result.add(item);
		}
		
		return result;
	}

	@SuppressWarnings("unchecked")
	@Override
	@Transactional(propagation = Propagation.REQUIRES_NEW)
	public void saveAllocation(Integer from, Integer to, Integer allocationId, List<HashMap<String, Object>> json) throws InventoryShortageException {
		Allocation allocation = null;
		
		List<Goods> goodsList = goodsMapper.findGoodsByStoreId(from); 
		
		HashMap<String, Integer> stock = new HashMap<String, Integer>();
		HashMap<String, String> names = new HashMap<String, String>();
		
		for(Goods goods : goodsList) {
			stock.put(goods.getSku().toLowerCase(), goods.getStorage());
			names.put(goods.getSku().toLowerCase(), goods.getName());
		}
		
		if(allocationId > 0) {
			allocation = findAllocationById(allocationId);
			
			if(allocation == null)
				allocationId = 0;
		}
		
		if(allocationId > 0) {
			for(HashMap<String, Object> map : json) {
				CustomHashMap<String, Object> item = CustomHashMap.convert(map);
				
				String sku = item.getString("goods_sku");
				String name = names.get(sku.toLowerCase());
				Integer storage = stock.get(sku.toLowerCase());
				Integer quantity = item.getInteger("quantity");
				
				if((storage - quantity) < 0) {
					throw new InventoryShortageException(name + " 库存不足");
				}
				
				AllocationDetail entity = new AllocationDetail();
				entity.setAllocationId(allocationId);
				entity.setGoodsId(item.getInteger("goods_id"));
				entity.setGoodsSku(item.getString("goods_sku"));
				entity.setQuantity(quantity);
				updateAllocationDetail(entity);
			}
			updateAllocation(allocation);
		} else {
			
			String sn = SerialNumber.getSN(SerialNumber.ALLOCATION, from);
			
			allocation = new Allocation();
			allocation.setSn(sn);
			allocation.setStatus(0);
			allocation.setFromId(from);
			allocation.setToId(to);
			
			insertAllocation(allocation);
			
			allocationId = allocation.getId();
			
			for(HashMap<String, Object> map : json) {
				CustomHashMap<String, Object> item = CustomHashMap.convert(map);
				
				String sku = item.getString("goods_sku");
				String name = names.get(sku.toLowerCase());
				Integer storage = stock.get(sku.toLowerCase());
				Integer quantity = item.getInteger("quantity");
				
				if((storage - quantity) < 0) {
					throw new InventoryShortageException(name + " 库存不足");
				}
				
				AllocationDetail entity = new AllocationDetail();
				entity.setAllocationId(allocationId);
				entity.setSn(sn);
				entity.setGoodsId(item.getInteger("goods_id"));
				entity.setGoodsSku(item.getString("goods_sku"));
				entity.setQuantity(quantity);
				
				insertAllocationDetail(entity);
			}
			
			allocation.setStatus(1);
			updateAllocation(allocation);
		}
	}

	@Override
	@Transactional(propagation = Propagation.REQUIRES_NEW)
	public void confirm(Allocation allocation) throws InventoryShortageException{
		allocation.setStatus(2);
		updateAllocation(allocation);
		
		Integer allocationId = allocation.getId();
		Integer from = allocation.getFromId();
		Integer to = allocation.getToId();

		List<Goods> goods1 = goodsMapper.findGoodsByStoreId(from);
		List<Goods> goods2 = goodsMapper.findGoodsByStoreId(to);
		
		HashMap<Integer, Integer> storageMapping1 = new HashMap<Integer, Integer>();
		HashMap<Integer, Integer> storageMapping2 = new HashMap<Integer, Integer>();
		HashMap<Integer, Integer> refStorageMapping1 = new HashMap<Integer, Integer>();
		HashMap<Integer, Integer> refStorageMapping2 = new HashMap<Integer, Integer>();
		
		for(Goods item : goods1) {
			storageMapping1.put(item.getId(), item.getStorage());
			refStorageMapping1.put(item.getId(), item.getRefStorage());
		}
		
		for(Goods item : goods2) {
			storageMapping2.put(item.getId(), item.getStorage());
			refStorageMapping2.put(item.getId(), item.getRefStorage());
		}
		
		List<AllocationDetail> list = findAllocationDetailByAllocationId(allocationId);
		
		Integer storage, refStorage, goodsId;
		
		for(AllocationDetail item : list) {
			goodsId = item.getGoodsId();
			storage = storageMapping1.get(goodsId) - item.getQuantity();
			refStorage = refStorageMapping1.get(goodsId) - item.getQuantity();
			
			if(storage < 0) {
				throw new InventoryShortageException(item.getGoodsName() + " 库存不足");
			}
			
			goodsMapper.updateGoodsStorage(from, goodsId, storage);
			goodsMapper.updateGoodsRefStorage(from, goodsId, refStorage);

			storage = storageMapping2.get(goodsId) + item.getQuantity();
			refStorage = refStorageMapping2.get(goodsId) + item.getQuantity();
			goodsMapper.updateGoodsStorage(to, goodsId, storage);
			goodsMapper.updateGoodsRefStorage(to, goodsId, storage);
		}
		
	}

	@Override
	public QueryResult queryAllocation(QueryAllocation query) {
		QueryResult result = new QueryResult();
		result.setPage(query.getPage());
		result.setPageSize(query.getPageSize());
		result.setTotalRecord(mapper.queryAllocationCount(query));
		result.setData(mapper.queryAllocation(query));
		return result;
	}

	@Override
	public Allocation findAllocationBySN(String sn) {
		return mapper.findAllocationBySN(sn);
	}

}
